package com.yuxl.common.auth.utils;

import com.alibaba.fastjson2.JSONObject;
import com.yuxl.common.auth.config.JwtParameter;
import com.yuxl.common.core.domain.auth.JwtUser;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.security.Key;
import java.util.Date;

/**
 * @author yuxl
 */
@Component
public class JwtUtil {
    private final Key key;
    private final JwtParameter jwtParameter;

    public JwtUtil(JwtParameter jwtParameter) {
        String secret = jwtParameter.getStore();
        this.key = Keys.hmacShaKeyFor(secret.getBytes());
        this.jwtParameter = jwtParameter;
    }

    public String generateToken(JwtUser jwt) {
        return Jwts.builder()
                .setSubject(JSONObject.toJSONString(jwt))
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + jwtParameter.getExpirationTime()*1000))
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();
    }

    public JwtUser getJwtFromToken(String token) {
        String subject = Jwts.parserBuilder()
                .setSigningKey(key)
                .build()
                .parseClaimsJws(token)
                .getBody()
                .getSubject();
        return JSONObject.parseObject(subject, JwtUser.class);
    }


    public String getToken(ServerHttpRequest request){
        String authHeader = request.getHeaders().getFirst(jwtParameter.getHeaders());
        if (authHeader != null && !authHeader.isEmpty()) {
            return authHeader;
        }
        return null;
    }
    public String getToken(ServerWebExchange exchange){
        String authHeader = exchange.getRequest().getHeaders().getFirst(jwtParameter.getHeaders());
        if (authHeader != null && !authHeader.isEmpty()) {
            return authHeader;
        }
        return null;
    }



    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
            return true;
        } catch (JwtException | IllegalArgumentException e) {
            return false;
        }
    }

    public Mono<JwtUser> getCurrentUser() {
        return ReactiveSecurityContextHolder.getContext()
                .map(SecurityContext::getAuthentication)
                .filter(Authentication::isAuthenticated)
                .flatMap(auth -> {
                    String token = null;
                    if (auth.getCredentials() != null) {
                        token = auth.getCredentials().toString();
                        return Mono.just(getJwtFromToken(token));
                    }else{
                        return Mono.empty();
                    }
                });
    }
}
